﻿
/*============== simpleIRC - http://matthias.van-eeghem.com/ ==============*
 *                                                                         *
 *  File: Colors.cs                                                        *
 *  Project: simpleIRC                                                     *
 *  Author(s): Matthias Van Eeghem <matthias@van-eeghem.com>               *
 *                                                                         *
 * ========================================================================*
 *                                                                         *
 *  This program is free software: you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation, either version 3 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 *                                                                         *
===========================================================================*/

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;

namespace simpleIRC.UI
{
    /// <summary>
    /// This class contains all the Color related methods
    /// </summary>
    public class Colors
    {
        MainWindow mainWindow;

        /// <summary>
        /// The constructor of the Color class, this saves the instance of the MainWindow object in the mainWindow property.
        /// </summary>
        /// <param name="parentWindow">A reference to the MainWindow object</param>

        public Colors(MainWindow parentWindow)
        {
            mainWindow = parentWindow;
        }

        /// <summary>
        /// This function returns a TextPointer object from a character index
        /// </summary>
        /// <param name="startPointer">The StartPointer to start searching from</param>
        /// <param name="index">The index to get the TextPointer from</param>
        /// <returns>The TextPointer from the index</returns>

        private TextPointer GetPointerFromIndex(TextPointer startPointer, int index)
        {
            TextPointer ReturnPointer = startPointer;
            int i = 0;

            while (i < index && ReturnPointer != null)
            {
                if (ReturnPointer.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text || ReturnPointer.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.None)
                    i++;

                if (ReturnPointer.GetPositionAtOffset(1, LogicalDirection.Forward) == null)
                    return ReturnPointer;

                ReturnPointer = ReturnPointer.GetPositionAtOffset(1, LogicalDirection.Forward);
            }

            return ReturnPointer;
        }

        /// <summary>
        /// This function colorises the text between two string indices in the color passed on as third argument
        /// </summary>
        /// <param name="startIndex">The start index</param>
        /// <param name="endIndex">The end index</param>
        /// <param name="color">The color</param>
        /// <param name="mainWindow">The reference to the MainWindow object</param>

        private void ColoriseText(int startIndex, int endIndex, Brush color, MainWindow mainWindow)
        {
            TextSelection TextRange = mainWindow.ChatBox.Selection;
            TextPointer ContentStart = mainWindow.ChatBox.Document.ContentStart;
            TextPointer StartPosition = GetPointerFromIndex(ContentStart, startIndex);
            TextPointer EndPosition = GetPointerFromIndex(ContentStart, startIndex + endIndex);

            TextRange.Select(StartPosition, EndPosition);
            TextRange.ApplyPropertyValue(TextElement.ForegroundProperty, color);
        }

        /// <summary>
        /// This function returns a Brush from the a color index
        /// </summary>
        /// <param name="colorIndex">The color index</param>
        /// <returns>The Brush</returns>

        private Brush GetColorFromIndex(int colorIndex)
        {
            switch (colorIndex)
            {
                case 0: return Brushes.White;
                case 1: return Brushes.Black;
                case 2: return Brushes.DarkBlue;
                case 3: return Brushes.DarkGreen;
                case 4: return Brushes.Red;
                case 5: return Brushes.Brown;
                case 6: return Brushes.Purple;
                case 7: return Brushes.Orange;
                case 8: return Brushes.Yellow;
                case 9: return Brushes.LightGreen;
                case 10: return Brushes.CadetBlue;
                case 11: return Brushes.LightBlue;
                case 12: return Brushes.DarkBlue;
                case 13: return Brushes.Pink;
                case 14: return Brushes.DarkGray;
                case 15: return Brushes.LightGray;
                default: return Brushes.Black;
            }
        }

        /// <summary>
        /// This function returns the index from the color
        /// </summary>
        /// <param name="color">The color to get the index from</param>
        /// <returns>The index</returns>

        private int GetIndexFromColor(Brush color)
        {
            if (color == Brushes.White) return 0;
            if (color == Brushes.Black) return 1;
            if (color == Brushes.DarkBlue) return 2;
            if (color == Brushes.DarkGreen) return 3;
            if (color == Brushes.Red) return 4;
            if (color == Brushes.Brown) return 5;
            if (color == Brushes.Purple) return 6;
            if (color == Brushes.Orange) return 7;
            if (color == Brushes.Yellow) return 8;
            if (color == Brushes.LightGreen) return 9;
            if (color == Brushes.CadetBlue) return 10;
            if (color == Brushes.LightBlue) return 11;
            if (color == Brushes.DarkBlue) return 12;
            if (color == Brushes.Pink) return 13;
            if (color == Brushes.DarkGray) return 14;
            if (color == Brushes.LightGray) return 15;

            return 1;
        }

        /// <summary>
        /// This function applies the color constant and the color and returns the string 
        /// </summary>
        /// <param name="color">The color to append</param>
        /// <returns>The string with the color constant and the color integer from the brush</returns>

        public string ApplyColor(Brush color)
        {
            return Convert.ToChar(3) + "" + GetIndexFromColor(color);
        }

        /// <summary>
        /// This function searches all colors in a string and calls the ColoriseText() function to do so
        /// </summary>
        /// <param name="inputText">The input text to handle</param>

        public void HandleColors(string inputText)
        {
            // Do we have any input at all?
            if (inputText == null) return;

            // The color constant
            char ColorCharacter = Convert.ToChar(3);
            // Holds the total amount of characters removed from the string
            int Count = 0;

            List<int> ColorIndices = new List<int>();
            List<int> ColorCodes = new List<int>();

            // Search the string for colors
            Regex RegularExpression = new Regex(@"(" + ColorCharacter + "\\d{0,2})");
            MatchCollection MatchList = RegularExpression.Matches(inputText);

            // Loop through all the matches found
            foreach (Match Match in MatchList)
            {
                // Default color = 1 (black)
                int Color = 1;

                // We remove the color constant from the string
                string ColorString = Match.Value.Remove(0, 1);

                // Get the color as integer
                if (ColorString.Length == 1 || ColorString.Length == 2) Color = Convert.ToInt32(ColorString);

                // Add the color to the Lists, we substract the total amount of characters already removed from the index
                ColorCodes.Add(Color);
                ColorIndices.Add((Match.Index - Count));

                // Remove the color from the input string
                inputText = inputText.Remove((Match.Index - Count), Match.Value.Length);

                // Increment the amount of total characters removed
                Count += Match.Value.Length;
            }

            mainWindow.UsersTreeView.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { mainWindow.ChatBox.AppendText(inputText); }));

            // Loop through all the ColorList elements
            for (int i = 0; i < ColorCodes.Count; i++)
            {
                // Initialise all the variables
                int StartIndex = ColorIndices[i], Length = 0, Color = ColorCodes[i];

                // If this isn't the last element, the length to remove is equal to the next element minus the the current index
                if (i != (ColorCodes.Count - 1))
                {
                    Length = (ColorIndices[(i + 1)] - StartIndex);
                }
                // This is the last element in the dictionary, the length to remove is the text length minus the current index
                else
                {
                    Length = (inputText.Length - StartIndex);
                }

                mainWindow.UsersTreeView.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { ColoriseText(StartIndex, Length, GetColorFromIndex(Color), mainWindow); }));
            }
        }
    }
}
